package com.example.day03homework.DAO;

/**
 * basedao 通用dao层
 * 在jdbc中尝试使用连接池 优化
 *
 */

import com.example.day03homework.Utils.JDBCUtils;
import com.example.day03homework.POJO.Topic;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 通用dao
 * dao  父类
 * 抽象了对jdbc的基本操作
 *
 */
public class BaseDao {
    //连接池优化
    //先把池子遭好
    //需要个list 来放连接，就new一个list  这里用链表数据结构的list 最省事
    static LinkedList<Connection> pool = new LinkedList<>();
    //连接上限
    static int linkMax = 5;

    //初始化
    static {
        //静态代码块进行遍历
        for (int i=0; i<linkMax; i++){
            try {
                Connection conn = JDBCUtils.getConnection();
                pool.addLast(conn);//一个一个放进链表
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //写连接优化
    public static Connection getConnection(){
        //先看有没有有连着的
        //若没有 先扩容
        if (pool.isEmpty()){
            for (int i=0; i<linkMax; i++){

                Connection conn = null; //初始化conn
                try {
                    conn = JDBCUtils.getConnection();
                    pool.addLast(conn); //又一个一个加
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("从连接池获取一个连接");
        return pool.removeFirst();//返回池子第一个连接
    }

   //归还
    public static void addBack(Connection conn){
        //将conn放在poll末尾即可
        pool.addLast(conn);
        System.out.println("归还一条连接");
    }



    public int updata(String sql,String... pam){
        //获取连接
        int j = 0;
        try{
            Connection conn = getConnection();
            //获取执行器  对sql进行与编译
            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            //添加参数
            for(int i = 0;i<pam.length;i++){
                String p = pam[i];
                preparedStatement.setString(1+i,p);
            }
            //执行sql  更新
            j = preparedStatement.executeUpdate();

            //释放
            JDBCUtils.close(null, null, conn);

        }catch (Exception e){
            e.printStackTrace();
            return j;

        }
        //返回
        return j;



    }

    /**
     * 使用PreparedStatement 进行对数据库 查询操作
     * @param sql
     * @param pam
     * @return
     */
    public ResultSet query(String sql,String... pam){
        //获取连接
        ResultSet res = null;
        try{
            Connection conn = JDBCUtils.getConnection();
            //获取执行器  对sql进行与编译
            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            //添加参数
            for(int i = 0;i<pam.length;i++){
                String p = pam[i];
                preparedStatement.setString(1+i,p);
            }
            //执行sql  更新
            res = preparedStatement.executeQuery();

            //conn 对象   有GC释放

        }catch (Exception e){
            e.printStackTrace();

        }
        return res;
    }

    //java 的反射机制  尝试看看什么是Java的反射机制  封装  查询操作
    //  反射  我们使用Java的反射机制  创建一个对象，使用相关方法

    public <T extends List<?>> T select(Class<?> cls,String sql,Object... pam)
    {
        //获取连接
        try{
            Connection conn = JDBCUtils.getConnection();
            //对sql进行预编译
            PreparedStatement preparedStatement = conn.prepareStatement(sql);
            //设置参数
            for(int i = 0;i<pam.length;i++){
                String p = (String) pam[i];
                preparedStatement.setString(1+i,p);
            }
            //执行sql
            ResultSet query = preparedStatement.executeQuery();
            //使用Java的反射机制
            //通过反射创建一个实体类对象。
            List<Object> data = new ArrayList<>();
            while (query.next()){
                //对结果集解析   解析区别：字段名不一样-----字段名====属
                //使用反射创建对象
                Object o = cls.newInstance();
                //获取全部属性
                Field[] declaredFields = cls.getDeclaredFields();
                //遍历
                for(Field f: declaredFields){
                    String name = f.getName();//属性名称
                    //设置该属性可以被访问
                    f.setAccessible(true);
                    //通过属性名称去去query  取值
                    Object object = query.getObject(name);
                    //设置属性的值
                    f.set(o,object);
                }
                data.add(o);
            }
            //关闭释放资源
            JDBCUtils.close(null, null, conn);

        }catch (Exception e){

        }




        return null;
    }
}
